import { Injectable, HttpStatus, Inject } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository, TreeRepository, IsNull } from 'typeorm';
import { Node } from './entities/node.entity';
import { CacheService } from '../common/services/cache.service';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { LoggerService } from '@nestjs/common';

@Injectable()
export class NodeService {
  constructor(
    @InjectRepository(Node)
    private readonly nodeRepository: TreeRepository<Node>,
    private readonly cacheService: CacheService,
    @Inject(WINSTON_MODULE_NEST_PROVIDER)
    private readonly logger: LoggerService,
  ) {}

  async findAll(): Promise<Node[]> {
    return this.nodeRepository.find();
  }

  // 创建树结构的节点
  async createNode(
    menuData: Partial<Node>,
    parentId?: number | null,
  ): Promise<Node> {
    this.logger.log(
      `创建节点: ${menuData.name}, parentId: ${parentId}`,
      'NodeService',
    );
    // 创建或更新节点时清除相关缓存
    await this.cacheService.del('node:tree');
    await this.cacheService.del('node:top');
    if (parentId) {
      await this.cacheService.del(`node:${parentId}:children`);
    }
    const menu = this.nodeRepository.create(menuData);
    // 初始化children和posts数组
    menu.children = [];
    menu.posts = [];

    if (parentId !== null && parentId !== undefined) {
      const parentNode = await this.nodeRepository.findOne({
        where: { id: parentId },
      });
      if (parentNode) {
        menu.parent = parentNode;
      }
    }

    // 如果有子节点，递归创建
    const children = menuData.children || [];
    const savedMenu = await this.nodeRepository.save(menu);
    this.logger.log(
      `节点创建成功: ${savedMenu.name}, id: ${savedMenu.id}`,
      'NodeService',
    );

    for (const childData of children) {
      // 确保子节点的parentId是当前节点的id
      childData.parentId = savedMenu.id;
      await this.createNode(childData, savedMenu.id);
    }

    return savedMenu;
  }
  // 获取节点树
  async getNodeTree(): Promise<any> {
    this.logger.log('获取节点树', 'NodeService');
    const cacheKey = 'node:tree';

    return await this.cacheService.getOrSet(
      cacheKey,
      async () => {
        this.logger.log('节点树缓存未命中，从数据库获取', 'NodeService');
        const nodes = await this.nodeRepository.find({
          order: { sort: 'ASC', id: 'ASC' },
        });
        const nodeTree = this.buildTree(nodes);
        return {
          code: HttpStatus.OK,
          data: nodeTree,
        };
      },
      3600,
    ); // 缓存1小时
  }

  // 构建节点树
  private buildTree(nodes: Node[], parentId: number | null = null): Node[] {
    const tree: Node[] = [];
    for (const node of nodes) {
      if (
        (parentId === null && node.parentId === null) ||
        (parentId !== null && node.parentId === parentId)
      ) {
        const nodeWithChildren = { ...node };
        const children = this.buildTree(nodes, node.id);
        nodeWithChildren.children = children;
        tree.push(nodeWithChildren);
      }
    }
    return tree;
  }

  // 获取指定节点的帖子列表
  async getPostsByNodeId(nodeId: number): Promise<any> {
    const cacheKey = `node:${nodeId}:posts`;

    return await this.cacheService.getOrSet(
      cacheKey,
      async () => {
        const node = await this.nodeRepository.findOne({
          where: { id: nodeId },
          relations: ['posts', 'posts.author'],
        });

        if (!node) {
          return {
            code: HttpStatus.NOT_FOUND,
            message: '节点不存在',
          };
        }

        return {
          code: HttpStatus.OK,
          data: node.posts,
        };
      },
      1800,
    ); // 缓存30分钟
  }

  // 获取所有顶级节点
  async getTopNodes(): Promise<any> {
    const cacheKey = 'node:top';

    return await this.cacheService.getOrSet(
      cacheKey,
      async () => {
        const nodes = await this.nodeRepository.find({
          where: { parentId: IsNull() },
          order: { sort: 'ASC' },
        });

        return {
          code: HttpStatus.OK,
          data: nodes,
        };
      },
      3600,
    ); // 缓存1小时
  }

  // 获取指定节点的子节点
  async getChildrenNodes(nodeId: number): Promise<any> {
    const cacheKey = `node:${nodeId}:children`;

    return await this.cacheService.getOrSet(
      cacheKey,
      async () => {
        const nodes = await this.nodeRepository.find({
          where: { parentId: nodeId },
          order: { sort: 'ASC' },
        });

        return {
          code: HttpStatus.OK,
          data: nodes,
        };
      },
      3600,
    ); // 缓存1小时
  }
}
